import {forEach, forIn, get, isEmpty, isNumber, isObject, isString, map} from 'lodash-es';

export function formatWan(val: number) {
    const v = val * 1;
    if (!v || Number.isNaN(v)) return '';

    let result: any = val;
    if (val > 10000) {
        result = Math.floor(val / 10000);
        result = `${result} W`;
    }
    return result;
}

/**
 * 数字保留多少位小数
 * @param num 数字
 * @param floatCnt 几位小数
 */
export function fuckJsFloat(num: any, floatCnt = 2) {
    let tmp = Math.pow(10, floatCnt);
    return isNumber(num) ? jhDivSimple(Math.round(jhMultiply(num, tmp)), tmp) : num;
    // return isNumber(num) ? Math.round(num * tmp) / tmp : num;
}

/**
 * 数字金额大写转换(可以处理整数,小数,负数)
 * @param money 数字金额
 * @returns {string}
 */
export function moneyToChinese(money: any) {
    let locale = localStorage.getItem('umi_locale');
    if ('zh-CN' !== locale) {
        return '';
    }
    let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']; //汉字的数字
    let cnIntRadice = ['', '拾', '佰', '仟']; //基本单位
    let cnIntUnits = ['', '万', '亿', '兆']; //对应整数部分扩展单位
    let cnDecUnits = ['角', '分', '毫', '厘']; //对应小数部分单位
    let cnInteger = '整'; //整数金额时后面跟的字符
    let cnIntLast = '元'; //整型完以后的单位
    let maxNum = 999999999999999.9999; //最大处理的数字
    let zeroCount;
    let IntLen;
    let decLen;

    let IntegerNum; //金额整数部分
    let DecimalNum; //金额小数部分
    let ChineseStr = ''; //输出的中文金额字符串
    let parts; //分离金额后用的数组，预定义
    if (money === '') {
        return '';
    }
    money = parseFloat(money);
    if (money >= maxNum) {
        // console.warning('超出最大处理数字');
        return '超出最大处理数字';
    }
    if (money === 0) {
        ChineseStr = cnNums[0] + cnIntLast + cnInteger;
        // ChineseStr = cnNums[0] + cnIntLast;
        //document.getElementById("show").value=ChineseStr;
        return ChineseStr;
    }

    let negative = false; // 是负数
    if (0 > money) {
        negative = true;
        money = `${money}`.substr(1);
    }

    money = money.toString(); //转换为字符串
    if (money.indexOf('.') === -1) {
        IntegerNum = money;
        DecimalNum = '';
    } else {
        parts = money.split('.');
        IntegerNum = parts[0];
        DecimalNum = parts[1].substr(0, 4);
    }
    if (parseInt(IntegerNum, 10) > 0) {//获取整型部分转换
        zeroCount = 0;
        IntLen = IntegerNum.length;
        for (let i = 0; i < IntLen; i++) {
            let n = IntegerNum.substr(i, 1);
            let p = IntLen - i - 1;
            let q = p / 4;
            let m = p % 4;
            if (n === '0') {
                zeroCount++;
            } else {
                if (zeroCount > 0) {
                    ChineseStr += cnNums[0];
                }
                zeroCount = 0; //归零
                ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
            }
            if (m === 0 && zeroCount < 4) {
                ChineseStr += cnIntUnits[q];
            }
        }
        ChineseStr += cnIntLast;
        //整型部分处理完毕
    }
    if (DecimalNum !== '') {//小数部分
        decLen = DecimalNum.length;
        for (let i = 0; i < decLen; i++) {
            let n = DecimalNum.substr(i, 1);
            if (n !== '0') {
                ChineseStr += cnNums[Number(n)] + cnDecUnits[i];
            }
        }
    }
    if (ChineseStr === '') {
        ChineseStr += cnNums[0] + cnIntLast + cnInteger;
        // ChineseStr += cnNums[0] + cnIntLast;
    } else if (DecimalNum === '') {
        ChineseStr += cnInteger;
    }
    return negative ? '负' + ChineseStr : ChineseStr;
}

// @ts-ignore
export function formatMoney(s, n = 0) {
    if (null === s || 'undefined' === typeof s || '' === s || isNaN(s)) {
        let num = 0;
        return num.toFixed(n);
    }
    let negative = false; // 是负数
    if (0 > s) {
        negative = true;
        s = `${s}`.substr(1);
    }
    n = n >= 0 && n <= 10 ? n : 2;
    s = parseFloat((s + '').replace(/[^\d\.-]/g, '')).toFixed(n) + '';
    let l = s.split('.')[0].split('').reverse(), r = s.split('.')[1];
    let t = '';
    for (let i = 0; i < l.length; i++) {
        t += l[i] + ((i + 1) % 3 === 0 && (i + 1) !== l.length ? ',' : '');
    }
    if (negative) t += '-';
    return t.split('').reverse().join('') + (n > 0 ? ('.' + r) : '');
}

// @ts-ignore
export function clearNoNum(value) {
    if (isNumber(value)) {
        value = `${value}`;
    }
    //修复第一个字符是小数点 的情况.
    if (!isString(value) || (value != '' && value.substr(0, 1) == '.')) {
        value = '';
    }
    value = value.replace(/^0*(0\.|[1-9])/, '$1');//解决 粘贴不生效
    value = value.replace(/[^\d.]/g, '');  //清除“数字”和“.”以外的字符
    value = value.replace(/\.{2,}/g, '.'); //只保留第一个. 清除多余的
    value = value.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
    value = value.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');//只能输入两个小数
    if (value.indexOf('.') < 0 && value != '') {//以上已经过滤，此处控制的是如果没有小数点，首位不能为类似于 01、02的金额
        if (value.substr(0, 1) == '0' && value.length == 2) {
            value = value.substr(1, value.length);
        }
    }
    return value;
}


/**
 * 将 B 转换成 K 或者 M
 * @param size
 * @private
 */
export function byte2KOM(size: number) {
    let reStr;

    if (1024 * 1024 <= size) { // M
        reStr = `${(size / (1024 * 1024)).toFixed(2)}M`;
    } else if (1024 <= size) { // K
        reStr = `${(size / (1024)).toFixed(2)}K`;
    } else {
        reStr = `${size}B`;
    }

    return reStr;
}

/**
 * 比如：getFloatPow(0.1,0.22, 0.333)，返回值是 1000。因为最大的小数位数是 3。
 * 最大的返回值时候 100000000
 * @param nums
 */
function getFloatPow(nums: any[]) {
    let maxCnt = 0;
    forIn(nums, arg => {
        let tmpNum = Number(arg);
        if (!isNaN(tmpNum)) {
            let fLen;
            try {
                fLen = tmpNum.toString().split(".")[1].length
            } catch (e) {
                fLen = 0
            }
            if (fLen > maxCnt) maxCnt = fLen;
        }
    });
    if (maxCnt > 8) maxCnt = 8;
    return Math.pow(10, maxCnt);
}

/**
 * 求和
 *
 * @return
 *
 */
export function jhAdd(...nums: any[]) {
    if (nums == null) {
        return 0;
    }
    let result = 0;
    let pow = getFloatPow(nums);
    forIn(nums, arg => {
        let tmpNum = Number(arg);
        if (!isNaN(tmpNum)) {
            result += Math.round(tmpNum * pow);
        }
    });
    return result / pow;
}

/**
 * 求差
 *
 * @return
 *
 */
export function jhSubtract(...nums: any[]) {
    if (nums == null) {
        return 0;
    }
    let pow = getFloatPow(nums);
    let result = Math.round((Number(nums[0]) || 0) * pow);
    forIn(nums, (arg, index) => {
        let n = Number(arg);
        // @ts-ignore
        if (index != 0 && !isNaN(n)) {
            result -= Math.round(n * pow);
        }
    });
    return result / pow;
}

/**
 * 求积
 *
 * @return
 *
 */
export function jhMultiply(...nums: any[]) {
    if (nums == null) {
        return 0;
    }
    let powCnt = 0;
    let result = 1;

    forIn(nums, (arg, index) => {
        let n = Number(arg);
        if (!isNaN(n)) {
            try {
                let l = n.toString().split('.')[1].length;
                if (l > 0) powCnt += l;
            } catch (e) {
            }
            n = Number(n.toString().replace('.', ''));
            // @ts-ignore
            if (index != 0) {
                result = result * n;
            } else {
                result = n;
            }
        }
    });
    let reVal = result / Math.pow(10, powCnt);
    if (powCnt > 8) reVal = Number(reVal.toFixed(8)); // 小数位数最多 8 位
    return reVal;
}

/**
 * 求商
 *
 * @return
 *
 */
export function jhDivide(...nums: any[]) {
    if (nums == null) {
        return 0;
    }
    let result = Number(nums[0]);
    if (isNaN(result) || result === 0) {
        return 0;
    }
    forIn(nums, (arg, index) => {
        let n = Number(arg);
        // @ts-ignore
        if (index != 0 && !isNaN(n)) {
            result = jhDivSimple(result, n);
        }
    });
    return Number(result.toFixed(8));
}

/**
 * 两个数的除法
 * @param num1
 * @param num2
 */
export function jhDivSimple(num1: any, num2: any) {
    let n1 = Number(num1);
    let n2 = Number(num2);

    if (isNaN(n1)) return 0;
    if (isNaN(n2)) return n1;

    let t1 = 0, t2 = 0, r1, r2;
    try {
        t1 = n1.toString().split(".")[1].length;
    } catch (e) {
    }
    try {
        t2 = n2.toString().split(".")[1].length;
    } catch (e) {
    }
    r1 = Number(n1.toString().replace(".", ""));
    r2 = Number(n2.toString().replace(".", ""));
    return (r1 / r2) * Math.pow(10, t2 - t1);
}

/**
 * 比较两个数是否相等
 * @param num1
 * @param num2
 */
export function jhIsNumberEqual(num1: number, num2: number) {
    return fuckJsFloat(num1, 2) == fuckJsFloat(num2, 2);
}

/**
 * 解析算式表达式。
 * 例如：
 * const srcData = {qty: 2, order: {price: 29.98}, goods: [{price: 9.9}]};
 * const expression = "($qty * ($order1.price - 10)) / 2 + $goods[0].price";
 * formatFormula(expression, srcData); // 即相当于运算 2 * (29.98 - 10) / 2 + 9.9
 * @param expression {string} 算式表达式
 * @param srcData {IObj} 数据源
 * @param options {{floatNum: number, [x]: any}} 更多设置项。 floatNum: 小数点精度
 */
export function formatFormula(expression: string, srcData: IObj, options: IObj = {floatNum: 0}) {
    let returnContent = '';

    if (isString(expression) && !isEmpty(expression) && isObject(srcData)) {
        let floatNum = options && options.floatNum ? options.floatNum : 0;
        let newExpression = expression;
        const fieldsArr = getFormulaFields(newExpression);

        forEach(fieldsArr, (fieldName) => {
            let tmpV;

            if (fieldName.indexOf('.') > -1) {
                tmpV = get(srcData, fieldName);
            } else {
                // @ts-ignore
                tmpV = srcData[fieldName];
            }
            newExpression = newExpression.replace(eval(`/(\\\$${fieldName})/g`), tmpV);
        });

        try {
            returnContent = formatMoney(eval(newExpression), floatNum);
        } catch (e) {
            returnContent = newExpression;
        }
    }
    return returnContent;
}

/**
 * 获取“算式表达式 @expression”中涉及到的字段。
 * 例如：
 * getFormulaFields("($qty * ($order1.price - 10)) / 2 + $goods[0].price");
 * // 返回 ['qty', 'order1.price', 'goods[0].price']
 * @param expression {string} 算式表达式
 * @return {[*]} 字段名数组
 */
export function getFormulaFields(expression: string) {
    const matches = expression.match(/\$[0-9a-zA-Z_]+(\.[0-9a-zA-Z_]+)*/g);

    if (!isEmpty(matches)) {
        return map(matches, fName => fName.substr(1));
    } else {
        return [];
    }
}